<?php
namespace app\controller\api\module\game\components;

use app\components\traits\Singleton;
use app\controller\api\module\game\components\traits\Game;

class Room
{
    use Singleton, Game;
    protected string $modelName = 'room';

    /**
     * 创建房间
     * @return array
     */
    public function create(): array
    {
        $userRoomList = $this->checkInRooms();
        if(!empty($userRoomList)){
            return responseArrayMsg('您还有正在进行中的棋局，可选择连接或断开连接', 500, [
                'room_list' => array_column($userRoomList, 'room_id')
            ]);
        }
        $roomID = $this->generateRoomID($this->baseInfo['id'], 6);
        $res = $this->model->add([
            'uid' => $this->baseInfo['id'],
            'room_id' => $roomID,
            'generation_method' => 2,
            'state' => 1,
            'state_code' => 200,
            'addtime' => time()
        ]);
        $this->clearRoomCache();
        $this->createRoomIDCache($roomID);
        $this->setRoomCache([
            'player-' . $this->baseInfo['id'] => [
                'uid' => $this->baseInfo['id'],
                'homeowner' => 1,
            ]
        ]);
        putLog('/room/create/' . date('Ym/d') . '.log', '创建房间|接收的参数：' . json_encode(request()->param()) . '，处理结果：' . $res . PHP_EOL);
        return responseArrayMsg('创建成功', 200, ['room_id' => $roomID]);
    }

    /**
     * 进入房间
     * @param string $roomID
     * @return array
     */
    public function enter(string $roomID): array
    {
        $userRoomList = $this->checkInRooms();
        if(!empty($userRoomList)){
            return responseArrayMsg('您还有正在进行中的棋局，可选择连接或断开连接', 500, [
                'room_list' => array_column($userRoomList, 'room_id')
            ]);
        }
        $roomInfo = $this->checkRoomExist($roomID, 'id, opposite_uid');
        if($roomInfo['opposite_uid'] > 0){
            return responseArrayMsg('房间已满');
        }
        $result = $this->model->edit(['id' => $roomInfo['id']], ['opposite_uid' => $this->baseInfo['id']]);
        $this->createRoomIDCache($roomID);
        $this->setRoomCache([
            'player-' . $this->baseInfo['id'] => [
                'uid' => $this->baseInfo['id'],
                'homeowner' => 2,
            ]
        ]);
        putLog('/room/enter/' . date('Ym/d') . '.log', '加入房间|接收的参数：' . json_encode(request()->param()) . '，处理结果：' . $result . PHP_EOL);
        return $result ? responseArrayMsg('加入成功', 200) : responseArrayMsg('加入失败');
    }

    /**
     * 开始游戏
     * @param int $myChess
     * @param int $opponentChess
     * @return array
     */
    public function start(int $myChess, int $opponentChess): array
    {
        if(empty($myChess) or empty($opponentChess)){
            return responseArrayMsg('未收到双方棋子信息');
        }
        $roomInfo = $this->checkRoomExist();
        [$oppositeKey, $oppositeUID] = $this->getRoomCacheOpposite('uid');
        $chessArray = [ // value => mysql.field
            1 => 'white_uid',
            2 => 'black_uid',
        ];
        if($myChess > 0 and $opponentChess > 0 and $myChess == $opponentChess){
            return responseArrayMsg('不能选择相同颜色的棋子哦!请重新选择后再开始游戏');
        }
        if(!array_key_exists($myChess, $chessArray) or !array_key_exists($opponentChess, $chessArray)){
            return responseArrayMsg('双方存在一个错误的棋子颜色');
        }
        $res = Model('roomPlayerInfo')->add([
            'rid' => $roomInfo['id'],
            'match_id' => $this->generateMatchID($this->baseInfo['id'], 8),
            $chessArray[$myChess] => $this->baseInfo['id'],
            $chessArray[$opponentChess] => $oppositeUID,
            'starttime' => time(),
        ]);

        $this->setRoomCache([
            'player-' . $this->baseInfo['id'] => [
                'chess' => $myChess,
            ],
            $oppositeKey => [
                'chess' => $opponentChess,
            ],
        ]);
        putLog('/room/start/' . date('Ym/d') . '.log', '开始游戏|接收的参数：' . json_encode(request()->param()) . '，处理结果：' . $res . PHP_EOL);
        return responseArrayMsg('', 200);
    }

    /**
     * 退出房间
     * @return array
     */
    public function exit(): array
    {
        $roomInfo = $this->checkRoomExist();
        $roomCache = $this->checkRoomCache();
        if(empty($roomCache) or !isset($roomCache['player-' . $this->baseInfo['id']]['homeowner']) or empty($roomCache['player-' . $this->baseInfo['id']]['homeowner'])){
            return responseArrayMsg('系统繁忙66');
        }
        if(empty($roomInfo['id'])){
            return responseArrayMsg('系统繁忙7788');
        }
        if($roomCache['player-' . $this->baseInfo['id']]['homeowner'] == 1){
            //解散房间，房主离开房间
            $this->model->edit(['id' => $roomInfo['id']], ['state' => 2, 'state_code' => 206, 'close_time' => time()]);
            $this->clearRoomCache();
        }else{
            //非房主离开房间
            $this->model->edit(['id' => $roomInfo['id']], ['opposite_uid' => 0]);
            if(isset($roomCache['player-' . $this->baseInfo['id']])){   //正常逻辑，非bug，当房主解散房间时，通知玩家后，玩家不会请求接口
                unset($roomCache['player-' . $this->baseInfo['id']]);
            }
            $this->setRoomCache($roomCache, false);
            $this->delRoomIDCache();
        }
        return responseArrayMsg('', 200);
    }

    /**
     * 检测是否存在未结束的棋局
     * @return array
     */
    private function checkInRooms(): array
    {
        return $this->model->getList('(uid = ' . $this->baseInfo['id'] . ' or opposite_uid = ' . $this->baseInfo['id'] . ') and state = 1 and state_code = 200', 'room_id');
    }

    /**
     * 判断房间是否存在
     * @param string $roomID        房间编号
     * @param string $filed         展示的字段
     * @return array|string
     */
    private function checkRoomExist(string $roomID = '', string $filed = 'id'){
        $roomID = $roomID ? : getAPICaches('room_id_' . $this->baseInfo['id']);
        empty($roomID) and responseMsgExit('房间号不存在');
        $roomInfo = $this->model->getInfo(['room_id' => $roomID], !empty($filed) ? $filed . ', state, state_code' : 'id, state, state_code', ['addtime' => 'desc']);
        empty($roomInfo) and responseMsgExit('房间不存在');
        ($roomInfo['state'] != 1 or $roomInfo['state_code'] != 200) and responseMsgExit('房间已经关闭', 202);
        return $roomInfo;
    }

    /**
     * 生成房间号
     * @param int $uid
     * @param int $length
     * @return false|string
     */
    private function generateRoomID(int $uid, int $length = 10) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $random = '';
        for ($i = 0; $i < 12; $i++) {
            $random .= $characters[rand(0, strlen($characters) - 1)];
        }
        $combined = $uid . $random . 'roomID' . time();
        $roomID = strtoupper(substr(md5($combined), 0, $length));
        return $this->model->getInfo(['room_id' => $roomID, 'state' => 1, 'state_code' => 200], 'id') ? $this->generateRoomID($uid, $length) : $roomID;
    }

    /**
     * 生成棋局号
     * @param int $uid
     * @param int $length
     * @return false|string
     */
    private function generateMatchID(int $uid, int $length = 10) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $random = '';
        for ($i = 0; $i < 18; $i++) {
            $random .= $characters[rand(0, strlen($characters) - 1)];
        }
        $combined = $uid . $random . 'matchID' . time();
        $id = substr(md5($combined), 0, $length);
        return Model('roomPlayerInfo')->getInfo(['match_id' => $id, 'outcome' => 0], 'id') ? $this->generateMatchID($uid, $length) : $id;
    }
}